﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OOAD_Project_Engine.Foundation.Interfaces;
using OOAD_Project_Engine.Foundation.MyEventArgs;
using System.Collections;
using OOAD_Project_Engine.Domain.Components;

namespace OOAD_Project_Engine.Domain.Entities
{
    public abstract class EntityComponentCollection : IEntityComponentCollection
    {
        Dictionary<Type, IEntityComponent> components = new Dictionary<Type, IEntityComponent>();

        public T Find<T>() where T : IEntityComponent
        {
            Type type = typeof(T);

            if (components.ContainsKey(type))
            {
                return (T)components[type];
            }
            return default(T);
        }

        public List<T> FindAll<T>() where T : IEntityComponent
        {
            List<T> matches = new List<T>();
            IEntityComponent[] tmpComponents = new IEntityComponent[components.Values.Count];
            components.Values.CopyTo(tmpComponents, 0);

            for (int i = 0; i < tmpComponents.Length; i++)
            {
                if (tmpComponents[i] is T)
                {
                    matches.Add((T)tmpComponents[i]);
                }
            }
            return matches;
        }

        public bool Contains<T>() where T : IEntityComponent
        {
            return components.ContainsKey(typeof(T));
        }

        public bool Remove<T>() where T : IEntityComponent
        {
            if (components.ContainsKey(typeof(T)))
            {
                IEntityComponent component = components[typeof(T)];
                return Remove(component);
                //OnComponentRemoved(new EntityComponentEventArgs(component));
                //return component.Owner.Manager.Remove(component);
            }
            return false;
        }

        public bool Remove(IEntityComponent component)
        {
            Type t = component.GetType();

            if (components.ContainsKey(t))
            {
                component.Dispose();
                bool result = components.Remove(t);
                component.Owner.Manager.Remove(component);
                OnComponentRemoved(new EntityComponentEventArgs(component));
                return result;
            }
            return false;
        }

        public bool RemoveImmediate(IEntityComponent component)
        {
            bool t= components.Remove(component.GetType());
            return t;
        }

        public IEntityComponent this[Type key]
        {
            get
            {
                return components[key];
            }
        }

        public void Add(IEntityComponent item)
        {
            if (IsReadOnly)
            {
                throw new ArgumentException("The entity is read-only.");
            }
            if (!components.ContainsKey(item.GetType()))
            {
                components.Add(item.GetType(), item);
                OnComponentAdded(new EntityComponentEventArgs(item));
                if (item is IDrawableContent)
                {
                    IDrawableContent d = item as IDrawableContent;
                    d.LoadContent();
                }
            }
        }

        public event EventHandler<EntityComponentEventArgs> ComponentAdded;

        protected virtual void OnComponentAdded(EntityComponentEventArgs e)
        {
            if (ComponentAdded != null)
            {
                ComponentAdded(this, e);
            }
        }

        public event EventHandler<EntityComponentEventArgs> ComponentRemoved;

        protected virtual void OnComponentRemoved(EntityComponentEventArgs e)
        {
            if (ComponentRemoved != null)
            {
                ComponentRemoved(this, e);
            }
        }

        public void Clear()
        {
            IEnumerable<IEntityComponent> e = components.Values;

            List<IEntityComponent> list = new List<IEntityComponent>();
            foreach (IEntityComponent c in e)
                list.Add(c);

            for (int i = 0; i < list.Count; i++)
                Remove(list[i]);
        }

        public bool Contains(IEntityComponent item)
        {
            return components.Values.Contains(item);
        }

        public void CopyTo(IEntityComponent[] array, int arrayIndex)
        {
            throw new NotImplementedException();
        }

        public int Count
        {
            get { return components.Values.Count; }
        }

        public bool IsReadOnly
        {
            get;
            set;
        }

        public IEnumerator<IEntityComponent> GetEnumerator()
        {
            return components.Values.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return components.GetEnumerator();
        }

        public void Initialize()
        {
            foreach (IEntityComponent c in components.Values)
            {
                c.Initialize();
            }
        }
    }
}
